package cn.jly.spring.boot.cloud.config;

import cn.jly.spring.boot.cloud.cron.MyJob2;
import cn.jly.spring.boot.cloud.dao.UserRepository;
import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.*;

import java.util.Date;

/**
 * 一般在项目中，除非定时任务涉及到的业务实在是太简单，使用 @Scheduled 注解来解决定时任务，否则大部分情况可能都是使用 Quartz 来做定时任务。在 Spring Boot 中使用 Quartz ，只需要在创建项目时，添加 Quartz 依赖即可
 * <p>
 * Quartz 在使用过程中，有两个关键概念，一个是JobDetail（要做的事情），另一个是触发器（什么时候做），要定义 JobDetail，需要先定义 Job，Job 的定义有两种方式：
 * <p>
 * 第一种方式，直接定义一个Bean
 * 关于这种定义方式说两点：
 * <p>
 * 首先将这个 Job 注册到 Spring 容器中。
 * 这种定义方式有一个缺陷，就是无法传参。
 * <p>
 * 第二种定义方式，则是继承 QuartzJobBean 并实现默认的方法：
 * 和第1种方式相比，这种方式支持传参，任务启动时，executeInternal 方法将会被执行。
 * <p>
 * Job 有了之后，接下来创建类，配置 JobDetail 和 Trigger 触发器，如下
 * <p>
 * 关于这个配置说如下几点：
 * <p>
 * 0 JobDetail 的配置有两种方式：MethodInvokingJobDetailFactoryBean 和 JobDetailFactoryBean 。
 * 1 使用 MethodInvokingJobDetailFactoryBean 可以配置目标 Bean 的名字和目标方法的名字，这种方式不支持传参。
 * 2 使用 JobDetailFactoryBean 可以配置 JobDetail ，任务类继承自 QuartzJobBean ，这种方式支持传参，将参数封装在 JobDataMap 中进行传递。
 * 3 Trigger 是指触发器，Quartz 中定义了多个触发器，这里向大家展示其中两种的用法，SimpleTrigger 和 CronTrigger 。
 * 4 SimpleTrigger 有点类似于前面说的 @Scheduled 的基本用法。
 * 5 CronTrigger 则有点类似于 @Scheduled 中 cron 表达式的用法。
 *
 * @author lanyangji
 * @description QuartzConfig
 * @date 2020/12/18 下午 7:20
 */
@Configuration
public class QuartzConfig {

    @Autowired
    UserRepository userRepository;

    /**
     * --------------------------简单注入方式---------------------------------
     *
     * @return
     */
    @Bean
    public MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean() {
        final MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean();
        bean.setTargetBeanName("myJob");
        bean.setTargetMethod("sayHello");
        return bean;
    }

    /**
     * 触发器
     *
     * @return
     */
    @Bean
    public SimpleTriggerFactoryBean simpleTriggerFactoryBean(MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean) {
        final SimpleTriggerFactoryBean bean = new SimpleTriggerFactoryBean();
        bean.setStartTime(new Date());
        bean.setRepeatCount(5);
        bean.setJobDetail(methodInvokingJobDetailFactoryBean.getObject());
        bean.setRepeatInterval(3000);
        return bean;
    }

    /**
     * -----------------------------继承方式，支持传参----------------------------------
     *
     * @return
     */
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean() {
        final JobDetailFactoryBean bean = new JobDetailFactoryBean();
        bean.setJobClass(MyJob2.class);
        final JobDataMap map = new JobDataMap();
        map.put("userRepository", userRepository);
        bean.setJobDataMap(map);
        return bean;
    }

    @Bean
    public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean) {
        final CronTriggerFactoryBean bean = new CronTriggerFactoryBean();
        bean.setCronExpression("0/10 * * * * ?");
        bean.setJobDetail(jobDetailFactoryBean.getObject());
        return bean;
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean simpleTriggerFactoryBean,
                                                     CronTriggerFactoryBean cronTriggerFactoryBean) {
        final SchedulerFactoryBean bean = new SchedulerFactoryBean();
        bean.setTriggers(simpleTriggerFactoryBean.getObject(), cronTriggerFactoryBean.getObject());
        return bean;
    }
}
